#include <proc.h>
#include <elf.h>
#include <fs.h>

size_t ramdisk_read(void *buf, size_t offset, size_t len);
/* write `len' bytes starting from `buf' into the `offset' of ramdisk */
size_t ramdisk_write(const void *buf, size_t offset, size_t len);
void init_ramdisk();
size_t get_ramdisk_size();


#ifdef __LP64__
# define Elf_Ehdr Elf64_Ehdr
# define Elf_Phdr Elf64_Phdr
#else
# define Elf_Ehdr Elf32_Ehdr
# define Elf_Phdr Elf32_Phdr
#endif


static uintptr_t loader(PCB *pcb, const char *filename) {

  int fd = fs_open(filename,0,0);
  assert(fd != -1);
  
  Elf_Ehdr e_head;
  fs_read(fd,&e_head,sizeof(Elf_Ehdr));
  /* assert file is elf64 */
  assert(e_head.e_ident[EI_MAG0] == ELFMAG0);  assert(e_head.e_ident[EI_MAG1] == ELFMAG1);  
  assert(e_head.e_ident[EI_MAG2] == ELFMAG2);  assert(e_head.e_ident[EI_MAG3] == ELFMAG3);  
  assert(e_head.e_ident[EI_CLASS] == ELFCLASS64);  
  if(e_head.e_machine == EM_RISCV) Log("BIN ARCH=RISCV64");
  else if(e_head.e_machine == EM_X86_64) Log("BIN ARCH=x86 64");
  // assert(e_head.e_machine == EM_RISCV);//assert file arch is riscv64
  Elf_Phdr e_phdr[e_head.e_phnum];
  fs_lseek(fd,e_head.e_phoff,SEEK_SET);
  fs_read(fd,(void *)e_phdr,e_head.e_phnum*e_head.e_phentsize);
  for (size_t i = 0; i < e_head.e_phnum; i++)
  {
    if(e_phdr[i].p_type != PT_LOAD) continue;
    
    fs_lseek(fd,e_phdr[i].p_offset,SEEK_SET);
    fs_read(fd,(void *)e_phdr[i].p_vaddr,e_phdr[i].p_filesz);
    memset((void *)e_phdr[i].p_vaddr+e_phdr[i].p_filesz,0,e_phdr[i].p_memsz-e_phdr[i].p_filesz);
  }
  
  return e_head.e_entry;
}

void naive_uload(PCB *pcb, const char *filename) {
  Log("naive_uload:%s",filename);
  uintptr_t entry = loader(pcb, filename);
  Log("Jump to entry = %p", entry);
  ((void(*)())entry) ();
}

